package com.wxg.filter;

import com.wxg.config.IgnoreUrlsProperties;
import com.wxg.service.PermissionService;
import com.wxg.utils.IpUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

/**
 * 请求url权限校验
 */
@Slf4j
@Configuration
public class AccessGatewayFilter implements GlobalFilter {

    private static final String TOKEN = "token";

    @Autowired
    private IgnoreUrlsProperties ignoreUrlsConfig;
    @Autowired
    private PermissionService permissionService;

    /**
     * 提供签权的feign客户端
     */

    /**
     * 1.首先网关检查token是否有效，无效直接返回401，不走签权逻辑
     * 2.走签权逻辑看是否对该请求有权限，有权限进入下一个filter，没有权限返回401
     * @param exchange
     * @param chain
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String token = request.getHeaders().getFirst(TOKEN);
        String method = request.getMethodValue();
        String url = request.getPath().value();
        String host = request.getRemoteAddress().getHostName();
        String ip = IpUtil.getIpAddress(request);
        log.debug("url:{},method:{},host:{},ip:{}", url, method, host, ip);
        //option请求直接放行
        if(request.getMethod()== HttpMethod.OPTIONS){
            return chain.filter(exchange);
        }
        //不需要网关签权的url
        if (ignore(url)) {
            return chain.filter(exchange);
        }
        //调用签权服务看用户是否有权限，若有权限进入下一个filter
        if (permissionService.permission(token, url, method)) {
            //通过校验的将uid设置到header上，后面服务可以直接获取当前用户，无需重复解析token TODO
            String userStr = "uid";
            log.debug("AccessGatewayFilter.filter() user:{}",userStr);
            ServerHttpRequest.Builder builder = request.mutate();
            builder.header("uid", userStr).build();
            return chain.filter(exchange.mutate().request(builder.build()).build());
        }
        return unauthorized(exchange);
    }

    /**
     * 网关拒绝，返回401
     *
     * @param
     */
    private Mono<Void> unauthorized(ServerWebExchange serverWebExchange) {
        serverWebExchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
        DataBuffer buffer = serverWebExchange.getResponse()
                .bufferFactory().wrap(HttpStatus.UNAUTHORIZED.getReasonPhrase().getBytes());
        return serverWebExchange.getResponse().writeWith(Flux.just(buffer));
    }

    /**
     * 检查是否忽略url
     * @param path 路径
     * @return boolean
     */
    private boolean ignore(String path) {
        PathMatcher pathMatcher = new AntPathMatcher();
        for(String ignoreUrl : ignoreUrlsConfig.getUrls()){
            if (pathMatcher.match(ignoreUrl, path)) {
                return true;
            }
        }
        return false;
    }
}
